package system.train;

import java.util.LinkedList;
import system.track.Block;
import system.track.Direction;
import system.track.IllegalFunctionCallException;

/**
 * This class is an implementation of the Train interface
 * and is subject to modifications.
 * 
 * @author Yasmine Kandissounon
 * @version Cycle 1 - complete
 */
public class ConcreteTrain implements Train, Runnable
{
    // the train will be initialized with a Block starting location
    private Block currentBlock;
    // the train will be initialized with a Route containing a set of
    // actions to be performed
    private Route currentRoute;
    private boolean waiting;
    private boolean running;
    private int speed;
    private Direction currentDirection;
    
    /**
     * Constructor for Objects of class ConcreteTrain.
     * 
     * @param block a Block indicating the starting location of
     * the train
     */
    public ConcreteTrain(Block block)
    {
        currentBlock = block;
        waiting = false;
        running = true;
        speed = 0; // the train is initially stopped
    }
    
    /**
     * Sets the Route for the train, based on the direction of travel.
     * The Route contains actions that the train will perform.
     * 
     * @param direction a Direction, either clockwise or counterclockwise
     * @return  a Route based on the given direction, containing 
     * instructions for the train
     */
    public Route setRoute(Direction direction)
    {
        return currentRoute = Route.createRoute(direction);
    }

    /**
     * Sets the Direction in which the train is oriented.
     * 
     * @param direction the Direction the train is pointed; either
     * clockwise or counterclockwise
     */
    public void setDirection(Direction direction)
    {
        currentDirection = direction;
    }
   
    /**
     * Returns the current Direction the train is headed.
     * 
     * @return  a Direction that the train is going; either clockwise
     * or counterclockwise
     */
    public Direction getDirection()
    {
        return currentDirection;
    }

    /**
     * Returns the Block where the train is currently located.
     * 
     * @return  a Block where the train is located
     */
    public Block getCurrentBlock()
    {
        return currentBlock; 
    }

    /**
     * Sets the current Block where the train is located; used for
     * initialization and error-checking purposes.
     * 
     * @param block a Block where the train's location will be set
     */
    public void setCurrentBlock(Block block)
    {
        currentBlock = block;
    }

    /**
     * Returns the train's current speed.
     * 
     * @return  an int from 0 to 7 indicating the speed of the train;
     * note that 0 means stopped
     */
    public int getSpeed()
    {
        return speed;
    }

    /**
     * Sets the speed of the train.
     * 
     * @param speed an int from 0 to 7 that the train's speed will
     * be set to; note that 0 means stopped
     */
    public void setSpeed(int speed)
    {
        // checks to make sure that the speed is valid
        if(speed > 0 || speed < 7)
        {
            this.speed = speed;
        }
    }

    /**
     * Stops the train; synchronized to pause the train thread as well.
     */
    public synchronized void stop()
    {
        running = false;
        RouteActions.STOP.executeAction(this);
//       notify();
    }

    /**
     * When a Sensor is tripped as the train passes over it, the train
     * may then execute further actions.  This method takes the train 
     * out of a "waiting" status.
     */
    public synchronized void tripSensor()
    {
        this.waiting = false;
        try
        {
            Thread.sleep(1000);
        }    
        catch(InterruptedException e)
        {
        }
//       notify();
    }

    /**
     * Waits for a Sensor by sleeping for 1 beat as long as the
     * "waiting" status is true.
     */
    private void waitForSensor()
    {
        try
        {
            while(waiting)
            {
                Thread.sleep(1);
            }
        }
        catch(InterruptedException e)
        {
        }
    }

    /**
     * The run method which initiates the train's thread.
     */
    public void run()
    {
        while(running)
        {
            while(!waiting)
            {
                // executes Route actions, each in turn
                waiting = currentRoute.executeNextAction(this);
            }
            waitForSensor();
        }
    }
}
